package com.tiancheng.trade.merchant.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.tiancheng.trade.commom.core.utils.IdWorkerUtils;
import com.tiancheng.trade.commom.web.model.response.MerchantPayRegFileResVO;
import com.tiancheng.trade.merchant.dto.requestdto.BucketPolicyConfigDto;
import com.tiancheng.trade.merchant.dto.requestdto.MinioUploadDto;
import com.tiancheng.trade.merchant.service.IUploadService;
import io.minio.*;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author: kellen
 * @Description:
 * @Date: create in 2024/12/24 14:45
 */
@Slf4j
@Service
public class UploadServiceImpl implements IUploadService {

    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Value("${minio.publicEndpoint}")
    private String PUBLIC_ENDPOINT;
    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.accessKey}")
    private String ACCESS_KEY;
    @Value("${minio.secretKey}")
    private String SECRET_KEY;

    @Override
    public MinioUploadDto upload(MultipartFile file) {
        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
            if (isExist) {
                log.info("存储桶已经存在！");
            } else {
                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
                BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(BUCKET_NAME);
                SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder().bucket(BUCKET_NAME).config(JSONUtil.toJsonStr(bucketPolicyConfigDto)).build();
                minioClient.setBucketPolicy(setBucketPolicyArgs);
            }
            String fileId = IdWorkerUtils.getInstance().buildPartNumber();
            String filename = genFileName(file.getOriginalFilename(), fileId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + filename;
            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).contentType(file.getContentType()).stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
            minioClient.putObject(putObjectArgs);
            log.info("文件上传成功!");
            MinioUploadDto minioUploadDto = new MinioUploadDto();
            minioUploadDto.setFileId(fileId);
            minioUploadDto.setName(filename);
            minioUploadDto.setUrl(PUBLIC_ENDPOINT + "/" + BUCKET_NAME + "/" + objectName);
            return minioUploadDto;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("上传发生错误: {}！", e.getMessage());
        }
        return null;
    }

    @Override
    public MultipartFile downLoad(String filePath) throws Exception {

        String[] split = filePath.split("/");
        StringBuilder objectName = new StringBuilder();
        for (int i = 0; i < split.length; i++) {
            if (i == split.length - 2) {
                objectName.append(split[i]);
            }
            if (i == split.length - 1) {
                objectName.append("/").append(split[i]);
            }
        }

        MinioClient minioClient = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        // 从MinIO下载文件
        InputStream inputStream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(BUCKET_NAME)
                        .object(objectName.toString())
                        .build()
        );

        // 将InputStream转换为字节数组
        byte[] bytes = inputStream.readAllBytes();

        // 创建自定义的MultipartFile实现
        return new MultipartFile() {
            @Override
            public String getName() {
                return objectName.toString().split("/")[1];
            }

            @Override
            public String getOriginalFilename() {
                return objectName.toString().split("/")[1];
            }

            @Override
            public String getContentType() {
                // 你可以根据文件类型设置合适的Content-Type
                return "application/octet-stream";
            }

            @Override
            public boolean isEmpty() {
                return bytes.length == 0;
            }

            @Override
            public long getSize() {
                return bytes.length;
            }

            @Override
            public byte[] getBytes() throws IOException {
                return bytes;
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return new ByteArrayInputStream(bytes);
            }

            @Override
            public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
                // 将文件写入目标路径
                java.nio.file.Files.write(dest.toPath(), bytes);
            }
        };
    }

    private String genFileName(String originalFilename, String fileId) {
        if (originalFilename.contains(".")) {
            String fileNameSuffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            return fileId + "." + fileNameSuffix;
        }
        return originalFilename;
    }

    private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
        BucketPolicyConfigDto.Statement statement = BucketPolicyConfigDto.Statement.builder().Effect("Allow").Principal("*").Action("s3:GetObject").Resource("arn:aws:s3:::" + bucketName + "/*.**").build();
        return BucketPolicyConfigDto.builder().Version("2012-10-17").Statement(CollUtil.toList(statement)).build();
    }
}
